package cc.magicjson.easy.batch.builder;

import cc.magicjson.easy.batch.config.BatchSqlProvider;
import cc.magicjson.easy.batch.core.BatchParameterExtractor;
import cc.magicjson.easy.batch.core.BatchProcessor;
import cc.magicjson.easy.batch.core.BatchProgressCallback;
import cc.magicjson.easy.batch.core.BatchStrategy;
import cc.magicjson.easy.batch.model.BatchContext;
import cc.magicjson.easy.batch.model.BatchResult;
import cc.magicjson.easy.batch.strategy.ParallelBatchStrategy;
import cc.magicjson.easy.batch.strategy.SimpleBatchStrategy;
import cc.magicjson.easy.batch.strategy.TransactionalBatchStrategy;
import cc.magicjson.easy.batch.template.SqlTemplate;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.transaction.support.TransactionTemplate;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * 批量操作构建器
 */
public class BatchOperationBuilder<T> {
    private final BatchProcessor<T> processor;
    private final BatchContext.BatchContextBuilder<T> contextBuilder;

    public BatchOperationBuilder(BatchProcessor<T> processor) {
        this.processor = processor;
        this.contextBuilder = BatchContext.<T>builder()  // 明确指定泛型类型
            .batchSize(processor.getDefaultBatchSize())
            .useTransaction(true)
            .allowPartialSuccess(false)
            .retryAttempts(0)
            .retryDelay(1000L)
            .parallel(false)
            .threadCount(Runtime.getRuntime().availableProcessors())
            .jdbcTemplate(processor.getJdbcTemplate())
            .transactionTemplate(processor.getTransactionTemplate())
            .sqlProvider(processor.getSqlProvider());
    }

    /**
     * 设置要处理的数据项
     */
    public BatchOperationBuilder<T> items(List<T> items) {
        contextBuilder.items(items);
        return this;
    }

    /**
     * 设置SQL键值
     */
    public BatchOperationBuilder<T> sqlKey(String sqlKey) {
        contextBuilder.sqlKey(sqlKey);
        return this;
    }

    /**
     * 设置参数提取器
     */
    public BatchOperationBuilder<T> parameterExtractor(
        BatchParameterExtractor<T> extractor) {
        contextBuilder.parameterExtractor(extractor);
        return this;
    }

    /**
     * 设置SQL模板
     */
    public BatchOperationBuilder<T> sqlTemplate(SqlTemplate template) {
        contextBuilder.sqlTemplate(template);
        contextBuilder.sqlKey(template.render());
        return this;
    }

    /**
     * 禁用事务
     */
    public BatchOperationBuilder<T> withoutTransaction() {
        contextBuilder.useTransaction(false);
        return this;
    }

    /**
     * 设置批处理大小
     */
    public BatchOperationBuilder<T> batchSize(int size) {
        contextBuilder.batchSize(size);
        return this;
    }

    /**
     * 允许部分成功
     */
    public BatchOperationBuilder<T> allowPartialSuccess() {
        contextBuilder.allowPartialSuccess(true);
        return this;
    }

    /**
     * 设置进度回调
     */
    public BatchOperationBuilder<T> withProgress(BatchProgressCallback callback) {
        contextBuilder.progressCallback(callback);
        return this;
    }

    /**
     * 设置重试参数
     */
    public BatchOperationBuilder<T> withRetry(int attempts, long delayMs) {
        contextBuilder.retryAttempts(attempts)
            .retryDelay(delayMs);
        return this;
    }

    /**
     * 启用并行处理
     */
    public BatchOperationBuilder<T> parallel() {
        contextBuilder.parallel(true);
        return this;
    }

    /**
     * 启用并行处理并设置线程数
     */
    public BatchOperationBuilder<T> parallel(int threadCount) {
        contextBuilder.parallel(true)
            .threadCount(threadCount);
        return this;
    }

    /**
     * 设置自定义JDBC模板
     */
    public BatchOperationBuilder<T> jdbcTemplate(JdbcTemplate jdbcTemplate) {
        contextBuilder.jdbcTemplate(jdbcTemplate);
        return this;
    }

    /**
     * 设置自定义事务模板
     */
    public BatchOperationBuilder<T> transactionTemplate(
        TransactionTemplate transactionTemplate) {
        contextBuilder.transactionTemplate(transactionTemplate);
        return this;
    }

    /**
     * 设置SQL提供者
     */
    public BatchOperationBuilder<T> sqlProvider(BatchSqlProvider sqlProvider) {
        contextBuilder.sqlProvider(sqlProvider);
        return this;
    }

    /**
     * 执行批处理操作
     */
    public BatchResult<T> execute() {
        BatchContext<T> context = contextBuilder.build();
        validateContext(context);
        BatchStrategy<T> strategy = determineStrategy(context);
        return strategy.execute(context);
    }

    /**
     * 验证上下文
     */
    private void validateContext(BatchContext<T> context) {
        if (CollectionUtils.isEmpty(context.getItems())) {
            throw new IllegalArgumentException("Items list cannot be empty");
        }
        if (!StringUtils.hasText(context.getSqlKey()) &&
            context.getSqlTemplate() == null) {
            throw new IllegalArgumentException(
                "Either sqlKey or sqlTemplate must be provided");
        }
        if (context.getParameterExtractor() == null) {
            throw new IllegalArgumentException("Parameter extractor must be provided");
        }
        if (context.getBatchSize() <= 0) {
            throw new IllegalArgumentException("Batch size must be positive");
        }
        if (context.isParallel() && context.getThreadCount() <= 0) {
            throw new IllegalArgumentException("Thread count must be positive");
        }
    }

    /**
     * 确定批处理策略
     */
    private BatchStrategy<T> determineStrategy(BatchContext<T> context) {
        if (context.isParallel()) {
            return new ParallelBatchStrategy<>();
        }
        if (context.isUseTransaction()) {
            return new TransactionalBatchStrategy<>();
        }
        return new SimpleBatchStrategy<>();
    }
}
